package com.fiume.travel.service.impl;

import com.fiume.travel.config.SnowflakeIdWorker;
import com.fiume.travel.constant.RedisConstant;
import com.fiume.travel.mapper.AffixMapper;
import com.fiume.travel.pojo.Affix;
import com.fiume.travel.pojo.AffixExample;
import com.fiume.travel.service.AffixService;
import com.fiume.travel.utils.BeanConv;
import com.fiume.travel.utils.EmptyUtil;
import com.fiume.travel.vo.AffixVo;
import org.redisson.Redisson;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * Description: 附件模块实现类 TODO: 使用一台独立的服务器处理图片信息
 * </p>
 *
 * @author fiume
 * @version v1.0.0
 * @create 2021-02-22 20:02
 * @see com.fiume.travel.service.impl
 */
@Service
public class AffixServiceImpl implements AffixService {

    @Resource
    AffixMapper affixMapper;

    @Resource
    SnowflakeIdWorker snowflakeIdWorker;

    @Value("${upLoad.pathRoot}")
    String pathRoot;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 文件上传
     *
     * @param multipartFile 上传对象
     * @param affixVo       附件对象
     * @return 附件对象
     * @throws IOException io异常
     */
    @Override
    public AffixVo upLoad(MultipartFile multipartFile, AffixVo affixVo) throws IOException {
        //判断文件是否为空
        if (multipartFile == null) {
            return null;
        }
        // 获取文件的类型
        String businessType = affixVo.getBusinessType();
        // 获取原始上传的文件名称 aaa.jpg
        String originalFilename = multipartFile.getOriginalFilename();

        //获取后缀名称 .jpg,以便于以后的数据清洗
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        affixVo.setSuffix(suffix);

        //生成一个唯一的文件名称
        String fileName = String.valueOf(snowflakeIdWorker.nextId());
        affixVo.setFileName(fileName + suffix);

        //构建访问路径
        String pathUrl = businessType + "/" + fileName + suffix;
        //判断业务类型的文件夹是否存在
        File file = new File(pathRoot + businessType);
        //文件夹不存在则创建
        if (!file.exists()) {
            file.mkdir();
        }
        file = new File(pathRoot + "/" + pathUrl);

        // 文件上传 TODO: 后续有时间的话,v2:使用nginx+tomcat构建一个独立的服务器用于图片存储(非)
        //  TODO: 使用FastDFS存储图片
        multipartFile.transferTo(file);
        affixVo.setPathUrl(pathUrl);
        Affix affix = BeanConv.toBean(affixVo, Affix.class);
        affixMapper.insert(affix);
        return BeanConv.toBean(affix, AffixVo.class);
    }

    /**
     * 为上传绑定对应的业务id(线路id)
     *
     * @param affixVo 附件对象
     * @return 是否成功
     */
    @Override
    public Boolean bindBusinessId(AffixVo affixVo) {
        Affix affix = BeanConv.toBean(affixVo, Affix.class);
        int i = affixMapper.updateByPrimaryKeySelective(affix);
        return i > 0;
    }

    /**
     * 按照业务id查询附件
     *
     * @param affixVo 附件对象
     * @return 附件对象列表
     */
    @Override
    public List<AffixVo> findAffixByBusinessId(AffixVo affixVo) {
        //1.从redis中获取数据
        // 创建一个缓存时使用的 key
        String key= RedisConstant.AFFIXSERVICE_FINDAFFIXBYBUSINESSID+affixVo.getBusinessId();
        // 获取对象桶位
        RBucket<List<AffixVo>> bucket = redissonClient.getBucket(key);
        // 从桶位中获取对应的数据
        List<AffixVo> affixesCache = bucket.get();
        if (!EmptyUtil.isNullOrEmpty(affixesCache)){
            //找到数据并返回
            return affixesCache;
        }

        //缓存中未找到相应数据就读取数据库
        AffixExample example = new AffixExample();
        example.createCriteria()
                .andBusinessIdEqualTo(affixVo.getBusinessId());
        List<Affix> affixList = affixMapper.selectByExample(example);

        // 将从mysql中的查询结果存放到Redis中
        if (!EmptyUtil.isNullOrEmpty(affixList)){
            /** set方法参数,FIXME:记不住,写下来,多记
             * 参数1: 被缓存的数据对象
             * 参数2: 缓存的时间
             * 参数3: 时间单位
             */
            bucket.set(BeanConv.toBeanList(affixList,AffixVo.class),1800, TimeUnit.SECONDS);
        }
        return BeanConv.toBeanList(affixList, AffixVo.class);
    }
}
